package com.dynaBlaster.elements;

import com.dynaBlaster.core.Direction;
import com.dynaBlaster.core.Point;
import com.dynaBlaster.game.Board;
import com.dynaBlaster.game.Game;
import com.dynaBlaster.game.GameConfig;
import com.dynaBlaster.view.BoardView;
import com.dynaBlaster.view.GameView;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;

public abstract class Creature extends Element {



	public boolean IS_FLYING = false;
	public boolean IS_PASSING_CREATURES = true;
	public Point pos;

	public static int CREATURE_ALIVE = 0;
	public static int CREATURE_DEAD = 1;
	private int state = CREATURE_ALIVE;

	Direction dir = Direction.EAST;

	public int speed;

	public int size;



	public Creature(Game game) {
		super(game);
		speed = game.board.tileSize / GameConfig.CREATURE_SPEED_FACTOR;
		size = game.board.tileSize / GameConfig.CREATURE_SIZE_FACTOR;// z
		// obcieciem
		
	}




	abstract public void move();

	Point nextAfterMove() {
		return checkMoveInDirection(dir);
	}

	Point checkMoveInDirection(Direction direction) {

		Point nextPos = new Point(this.pos);

		Point toCheck1 = null; // checking 2 corners facing move direction
		Point toCheck2 = null;

		switch (direction) {
		case NORTH:
			nextPos.y -= speed;

			toCheck1 = new Point(nextPos);
			toCheck1.x -= size;
			toCheck1.y -= size;

			toCheck2 = new Point(nextPos);
			toCheck2.x += size;
			toCheck2.y -= size;
			break;
		case SOUTH:
			nextPos.y += speed;

			toCheck1 = new Point(nextPos);
			toCheck1.x -= size;
			toCheck1.y += size;

			toCheck2 = new Point(nextPos);
			toCheck2.x += size;
			toCheck2.y += size;
			break;
		case EAST:
			nextPos.x += speed;

			toCheck1 = new Point(nextPos);
			toCheck1.x += size;
			toCheck1.y -= size;

			toCheck2 = new Point(nextPos);
			toCheck2.x += size;
			toCheck2.y += size;
			break;
		case WEST:
			nextPos.x -= speed;

			toCheck1 = new Point(nextPos);
			toCheck1.x -= size;
			toCheck1.y -= size;

			toCheck2 = new Point(nextPos);
			toCheck2.x -= size;
			toCheck2.y += size;
			break;
		}

		if (this.checkFree(toCheck1) && this.checkFree(toCheck2))
			return nextPos;
		else
			return null;

	}

	/**
	 * for cvreature computes all available directions. randomly chooses one of
	 * them and moves creature there. is no dir available stays in place and
	 * returns false
	 * 
	 * @return true if crature was moved false if it is blocked
	 */
	protected boolean moveInRandomFreeDirection() {
		int count = 0;
		Point next;
		Point[] tab = new Point[4];
		Direction[] tabDir = new Direction[4];

		this.setDir(Direction.NORTH);
		next = nextAfterMove();
		if (next != null) {
			tab[count] = next;
			tabDir[count] = Direction.NORTH;
			count++;
		}

		this.setDir(Direction.SOUTH);
		next = nextAfterMove();
		if (next != null) {
			tab[count] = next;
			tabDir[count] = Direction.SOUTH;
			count++;
		}

		this.setDir(Direction.EAST);
		next = nextAfterMove();
		if (next != null) {
			tab[count] = next;
			tabDir[count] = Direction.EAST;
			count++;
		}

		this.setDir(Direction.WEST);
		next = nextAfterMove();
		if (next != null) {
			tab[count] = next;
			tabDir[count] = Direction.WEST;
			count++;
		}

		if (count == 0)
			return false;
		if (count == 1) {
			this.setDir(tabDir[0]);
			this.pos = tab[0];
			return true;
		}

		int ind = game.random.nextInt(count);

		this.setDir(tabDir[ind]);
		this.pos = tab[ind];
		return true;
	}

	protected boolean checkFree(Point toCheck) {
		return board.isFree(toCheck, IS_PASSING_CREATURES, IS_FLYING);
	}

	public void setDir(Direction dir) {
		this.dir = dir;
	}

	public Direction getDir() {
		return this.dir;
	}

	public Point getPos() {
		return pos;
	}

	public void setPos(Point pos) {
		this.pos = pos;
	}

	/**
	 * returns true when this creature posisition, and its size provide covering
	 * of a point creatures are rectangular, not circular
	 * 
	 * @param toCheck
	 * @return
	 */
	public boolean isOverPoint(Point toCheck) {
		int dX = toCheck.x - pos.x;
		int dY = toCheck.y - pos.y;

		dX = Math.abs(dX);
		dY = Math.abs(dY);

		if (dX <= size && dY <= size)
			return true;
		else
			return false;
	}

	/**
	 * returns true when this creature touches other creatures are rectangular,
	 * not circular
	 */
	public boolean touchesCreature(Creature other) {
		int dX = other.pos.x - pos.x;
		int dY = other.pos.y - pos.y;

		dX = Math.abs(dX);
		dY = Math.abs(dY);

		if (dX < this.size + other.size && dY < this.size + other.size)
			return true;
		else
			return false;
	}

	protected boolean isOnFieldMiddle() {
		return (pos.x - size) % GameConfig.TILE_SIZE < GameConfig.CREATURE_isOnFieldMiddle
				&& (pos.y - size) % GameConfig.TILE_SIZE < GameConfig.CREATURE_isOnFieldMiddle;
	}

	public int getState() {
		return state;
	}

	public void kill() {
		this.state = CREATURE_DEAD;
	}

	public boolean isAlive() {
		return state == CREATURE_ALIVE;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((dir == null) ? 0 : dir.hashCode());
		result = prime * result + ((pos == null) ? 0 : pos.hashCode());
		result = prime * result + speed;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Creature other = (Creature) obj;
		if (dir == null) {
			if (other.dir != null)
				return false;
		} else if (!dir.equals(other.dir))
			return false;
		if (pos == null) {
			if (other.pos != null)
				return false;
		} else if (!pos.equals(other.pos))
			return false;
		if (speed != other.speed)
			return false;
		return true;
	}

}
